package biblioteca.servicio;

import biblioteca.dao.RolDao;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
import biblioteca.dao.SocioDao;
import biblioteca.persistencia.Rol;
import biblioteca.persistencia.Socio;
import com.google.appengine.api.datastore.Key;
import java.util.ArrayList;
import java.util.Iterator;
import javax.annotation.PostConstruct;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;

@Service(value = "socioServicio")
public class SocioServicioImpl implements SocioServicio {

    private SocioDao socioDao;
    private RolDao rolDao;

    @Autowired
    @Required
    public void setSocioDao(final SocioDao socioDao) {
        this.socioDao = socioDao;
    }

    @Autowired
    @Required
    public void setRolDao(final RolDao rolDao) {
        this.rolDao = rolDao;
    }

    @PostConstruct
    @Override
    public void preload_usuarios() {
        System.out.println("AQUI Cargar usuarios con poderes de admin o user o anonimo");
        socioDao.removeAll(Socio.class);
        rolDao.removeAll(Rol.class);

        Socio u1 = new Socio();
        u1.setNombre("adamin");// para probar
        u1.setDni("11111");

        Socio u2 = new Socio();
        u2.setNombre("user");// para probar
        u2.setDni("00000");

        Socio u3 = new Socio();
        u1.setNombre("anonimo");// para probar
        u1.setDni("anonimo");

        Rol r1 = new Rol();
        r1.setNombre("ADMIN");

        Rol r2 = new Rol();
        r2.setNombre("USER");

        Rol r3 = new Rol();
        r2.setNombre("ANONIMO");

        rolDao.insert(r1);
        rolDao.insert(r2);
        rolDao.insert(r3);

        addRol(u1, r1);
        addRol(u2, r2);
        addRol(u3, r3);

        create(u1);
        create(u2);
        create(u3);

        System.out.println("AQUI UsuarioServiceImpl preload_usuarios usuarios=" + socioDao.countAll(Socio.class));
    }

    @Override
    public void create(final Socio socio) {
        socioDao.insert(socio);
        System.out.println("create socio id= " + socio.getId());
    }

    @Override
    public void borrar(Key idSocio) {
        Socio socioborrar = socioDao.findByPK(Socio.class, idSocio);
        socioDao.remove(socioborrar);
    }

    @Override
    public Collection<Socio> getAllSocios() {
        return socioDao.getAll(Socio.class);
    }

    @Override
    public int countAllsocios() {
        return socioDao.countAll(Socio.class);
    }

    public Collection<Rol> getRoles(Socio socio) {
        Collection<Rol> roles = new ArrayList<Rol>();
        for (Key keyRol : socio.getRoles()) {
            Rol rol = rolDao.findByPK(Rol.class, keyRol);
            roles.add(rol);
        }
        return roles;
    }

    @Override
    public void addRol(Socio usuario, Rol rol) {
        usuario.getRoles().add(rol.getId());
    }

    @Override
    public UserDetails loadUserByUsername(String nombreUsuario) throws UsernameNotFoundException, DataAccessException {
        System.out.println("AQUI UsuarioServiceImpl loadUserByUsername usuarioDao=" + socioDao);
        Socio socio = socioDao.findByName(Socio.class, nombreUsuario);   //.findByPK(Socio.class, nombreUsuario);
        if (socio == null) {
            throw new UsernameNotFoundException("User not found: " + nombreUsuario);
        } else {
            return makeUser(socio);
        }
    }

    private org.springframework.security.core.userdetails.User makeUser(Socio socio) {
        return new org.springframework.security.core.userdetails.User(socio.getEmail(), socio.getDni(),
                true, true, true, true, makeGrantedAuthorities(socio));
    }

    private Collection<GrantedAuthority> makeGrantedAuthorities(Socio usuario) {
        Collection<GrantedAuthority> result = new ArrayList<GrantedAuthority>();
        int i = 0;
        for (Rol rol : getRoles(usuario)) {
            result.add(new GrantedAuthorityImpl(rol.getNombre()));
        }
        return result;
    }

    @Override
    public Socio getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.isAuthenticated()) {
            String username = authentication.getName();
            return getSocio(username);
        } else {
            return null;
        }
    }

    @PreAuthorize("isAuthenticated()")
    @Override
    public boolean isAdmin() {
        final String ROLE_ADMIN = "ADMIN";
        boolean isAdmin = false;
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        if (auth != null) {
            User user = ((User) auth.getPrincipal());
            Collection<GrantedAuthority> roles = user.getAuthorities();
            if (roles != null) {
                Iterator<GrantedAuthority> it = roles.iterator();
                while (!isAdmin && it.hasNext()) {
                    GrantedAuthority rol = it.next();
                    if (rol.getAuthority().equals(ROLE_ADMIN)) {
                        isAdmin = true;
                    }
                }
            }
        }
        return isAdmin;
    }

    @Override
    public Socio getSocio(String idUsuario) {
        return socioDao.findByName(Socio.class, idUsuario);
    }
}
